package site.jlopen.service.imp;

import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import site.jlopen.assets.oss.AwsOssConfig;
import site.jlopen.domain.datasource.KusciaDatasource;
import site.jlopen.domain.datasource.KusciaDatasourceNode;
import site.jlopen.domain.datasource.KusciaDatasourceOss;
import site.jlopen.domain.datasource.event.KusciaDatasourceEvent;
import site.jlopen.domain.datasource.event.KusciaDatasourceNodeEvent;
import site.jlopen.domain.datasource.event.KusciaDatasourceOssEvent;
import site.jlopen.domain.node.event.KusciaNodeEvent;
import site.jlopen.entity.BaseResponse;
import site.jlopen.entity.KusciaApiInfo;
import site.jlopen.entity.req.DatasourceReq;
import site.jlopen.kuscia.model.dataSource.KusciaDataSourceInfo;
import site.jlopen.kuscia.model.dataSource.KusciaOssDataSourceInfo;
import site.jlopen.kuscia.service.datasource.AbstractDataSourceManager;
import site.jlopen.mapper.datasource.KusciaDatasourceMapper;
import site.jlopen.mapper.datasource.KusciaDatasourceNodeMapper;
import site.jlopen.mapper.datasource.KusciaDatasourceOssMapper;
import site.jlopen.mapper.node.KusciaNodeMapper;
import site.jlopen.service.intf.datasource.DataSourceService;
import site.jlopen.service.intf.node.NodeService;
import site.jlopen.service.intf.oss.OssService;
import site.jlopen.utils.id.IdUtils;

@Service
public class DataSourceServiceImpl implements DataSourceService {
	private static Logger logger = LoggerFactory.getLogger(DataSourceServiceImpl.class);

	@Autowired
	private AbstractDataSourceManager dataSourceManager;
	@Autowired
	private KusciaNodeMapper nodeMapper;
	@Autowired
	private KusciaDatasourceMapper dataSourceMapper;
	@Autowired
	private KusciaDatasourceNodeMapper dataSourceNodeMapper;
	@Autowired
	private KusciaDatasourceOssMapper ossMapper;
	@Autowired
	private OssService ossService;
	@Autowired
	private NodeService nodeService;

	@Override
	public BaseResponse<String> createDataSource(Long userId, DatasourceReq req) {
		if (null == req.getId()) {
			req.setId(IdUtils.SnowFlakeId());
		}
		BaseResponse<String> ossRes = ossService.checkBucketExists(AwsOssConfig.builder().endpoint(req.getEndpoint()).accessKeyId(req.getAccessKey())
				.secretAccessKey(req.getAccessSecret()).build(), req.getBucket());
		if(ossRes.getStatus() != 0) {
			return ossRes;
		}
		if(req.getPrefix().startsWith("/") || req.getPrefix().endsWith("/")) {
			return new BaseResponse<String>().error("前缀属性前后不能出现/字符");
		}
		int saveOss = saveOss(req);
		if (saveOss > 0) {
			int row = 0;
			KusciaDatasource dsInfo = dataSourceMapper.selectByKey(req.getId());
			if (null == dsInfo) {
				dsInfo = new KusciaDatasource().setDatasourceId(req.getId()).setDatasourceUserId(userId)
						.setDatasourceName(req.getName())
						.setDatasourceCode(IdUtils.getRandom(null, 6))
						.setDatasourceType(req.getType()).setDatasourceInfoKey(null).setDatasourceAccessDirectly(1)
						.setDatasourceCreate(new Date());
				row = dataSourceMapper.insertSelective(dsInfo);
				if(row > 0) {
					List<KusciaDatasourceNode> dnlist = new ArrayList<KusciaDatasourceNode>();
					if(null != dnlist) {
						for (Long nodeId : req.getNodeIds()) {
							dnlist.add(new KusciaDatasourceNode()
									.setDnId(IdUtils.SnowFlakeId())
									.setDnDatasourceId(req.getId())
									.setDnNodeId(nodeId)
									.setDnStatus(0)
									.setDnCreate(new Date())
									);
						}
						if(dnlist.size() > 0) {
							dataSourceNodeMapper.insertBatch(dnlist);
						}
					}
				}
			} else {
				dsInfo.setDatasourceId(req.getId()).setDatasourceName(req.getName()).setDatasourceModified(new Date());
				row = dataSourceMapper.updateSelective(dsInfo);
			}
			if (row > 0) {
				return new BaseResponse<String>().success("保存成功");
			}
			return new BaseResponse<String>().error("保存失败");
		}
		return new BaseResponse<String>().error("保存OSS数据失败");
	}

	@Override
	public BaseResponse<String> updateDataSource(DatasourceReq req) {
		return new BaseResponse<String>().error("更新OSS数据失败");
	}

	private int saveOss(DatasourceReq req) {
		int row = 0;
		KusciaDatasourceOss ossInfo = ossMapper.selectByInfo(new KusciaDatasourceOss().setOssDatasourceId(req.getId()));
		if (null == ossInfo) {
			ossInfo = new KusciaDatasourceOss().setOssId(IdUtils.SnowFlakeId()).setOssDatasourceId(req.getId())
					.setOssEndpoint(req.getEndpoint()).setOssBucket(req.getBucket()).setOssPrefix(req.getPrefix())
					.setOssAccessKeyId(req.getAccessKey()).setOssAccessKeySecret(req.getAccessSecret())
					.setOssVirtualhost(req.getVirtualhost()).setOssVersion(req.getVersion())
					.setOssStorageType(req.getStorageType()).setOssCreate(new Date());
			row = ossMapper.insertSelective(ossInfo);
		} else {
			ossInfo.setOssEndpoint(req.getEndpoint()).setOssBucket(req.getBucket()).setOssPrefix(req.getPrefix())
					.setOssAccessKeyId(req.getAccessKey()).setOssAccessKeySecret(req.getAccessSecret())
					.setOssVirtualhost(req.getVirtualhost()).setOssVersion(req.getVersion())
					.setOssStorageType(req.getStorageType()).setOssModified(new Date());
			row = ossMapper.updateSelective(ossInfo);
		}
		return row;
	}

	@Override
	public BaseResponse<KusciaDatasourceEvent> getDataSource(Long dataSourceId) {
		KusciaDatasourceEvent dsInfo = dataSourceMapper.selectByKey(dataSourceId);
		KusciaDatasourceOssEvent ossInfo = ossMapper
				.selectByInfo(new KusciaDatasourceOss().setOssDatasourceId(dsInfo.getDatasourceId()));
		dsInfo.setDatasourceOss(ossInfo);
		List<KusciaDatasourceNodeEvent> nodes = nodeService.listByDsId(dataSourceId);
		dsInfo.setNodes(nodes);
		return new BaseResponse<KusciaDatasourceEvent>().success("succ", dsInfo);
	}

	@Override
	public KusciaDatasourceEvent getDataSource(Long userId, String datasourceCode) {
		KusciaDatasourceEvent dsInfo = dataSourceMapper.selectByInfo(new KusciaDatasource().setDatasourceUserId(userId).setDatasourceCode(datasourceCode));
		return dsInfo;
	}

	@Override
	public List<KusciaDatasourceEvent> list(Long userId) {
		Map<String, Object> records = new HashMap<String, Object>();
		records.put("datasourceUserId", userId);
		List<KusciaDatasourceEvent> list = dataSourceMapper.selectAllNotPage(records);
		for (KusciaDatasourceEvent dataSourceEvent : list) {
			KusciaDatasourceOssEvent ossInfo = ossMapper
					.selectByInfo(new KusciaDatasourceOss().setOssDatasourceId(dataSourceEvent.getDatasourceId()));
			dataSourceEvent.setDatasourceOss(ossInfo);
			List<KusciaDatasourceNodeEvent> nodes = nodeService.listByDsId(dataSourceEvent.getDatasourceId());
			dataSourceEvent.setNodes(nodes);
		}
		return list;
	}

	@Override
	public BaseResponse<String> restatus(Long datasourceId, Long nodeId) {
		KusciaDatasourceNode info = dataSourceNodeMapper.selectByInfo(
				new KusciaDatasourceNode().setDnDatasourceId(datasourceId).setDnNodeId(nodeId));

		KusciaNodeEvent node = nodeMapper.selectByKey(nodeId);
		KusciaApiInfo apiInfo = new KusciaApiInfo(node.getNodeProtocol(), node.getNodeGrpc()).ext(node.getNodeToken(), node.getNodeCert(), node.getNodeKey(), node.getNodeCa());
		// 预设为不可用
		info.setDnStatus(1);
		if (null == info.getDnDsId()) {
			KusciaDatasourceEvent dsInfo = dataSourceMapper.selectByKey(datasourceId);
			KusciaDatasourceOssEvent ossInfo = ossMapper
					.selectByInfo(new KusciaDatasourceOss().setOssDatasourceId(datasourceId));
			KusciaOssDataSourceInfo dsOss = new KusciaOssDataSourceInfo(ossInfo.getOssEndpoint(), ossInfo.getOssBucket(), 
					ossInfo.getOssPrefix(), ossInfo.getOssAccessKeyId(), ossInfo.getOssAccessKeySecret());
			String dsId = dataSourceManager.createDatasource(apiInfo, node.getNodeCode(), dsInfo.getDatasourceName(), dsOss);
			info.setDnDsId(dsId);
		}else {
			KusciaDataSourceInfo dsQuery = dataSourceManager.queryDataSource(apiInfo, node.getNodeCode(),
					info.getDnDsId());
			if (null == dsQuery) {
				return new BaseResponse<String>().error("数据源未配置");
			}
			info.setDnDsId(dsQuery.getDatasourceId());
		}
		if(StringUtils.isNotBlank(info.getDnDsId())) {
			info.setDnStatus(0);
		}
		int row = dataSourceNodeMapper.updateSelective(info);
		if(row > 0) {
			return new BaseResponse<String>().success("已刷新");
		}
		return new BaseResponse<String>().error("刷新失败");
	}

	@Override
	public BaseResponse<String> remove(Long datasourceId) {
		KusciaDatasourceOssEvent ossInfo = ossMapper
				.selectByInfo(new KusciaDatasourceOss().setOssDatasourceId(datasourceId));
		if(null != ossInfo) {
			ossMapper.deleteByKey(ossInfo.getOssId());
		}
		dataSourceMapper.deleteByKey(datasourceId);
		Map<String, Object> dsnmap = new HashMap<String, Object>();
		dsnmap.put("dnDatasourceId", datasourceId);
		List<KusciaDatasourceNodeEvent> nds = dataSourceNodeMapper.selectAllNotPage(dsnmap);
		for (KusciaDatasourceNodeEvent ndinfo : nds) {
			try {
				KusciaNodeEvent node = nodeMapper.selectByKey(ndinfo.getDnNodeId());
				KusciaApiInfo apiInfo = new KusciaApiInfo(node.getNodeProtocol(), node.getNodeGrpc())
						.ext(node.getNodeToken(), node.getNodeCert(), node.getNodeKey(), node.getNodeCa());
				dataSourceNodeMapper.deleteByKey(ndinfo.getDnId());
				dataSourceManager.removeDataSource(apiInfo, node.getNodeCode(), ndinfo.getDnDsId());
			} catch (Exception e) {
				continue;
			}
		}
		return new BaseResponse<String>().success("已删除");
	}

	@Override
	public BaseResponse<String> bindNode(Long dataSourceId, Long nodeId) {
		KusciaDatasourceNode info = dataSourceNodeMapper.selectByInfo(
				new KusciaDatasourceNode().setDnDatasourceId(dataSourceId).setDnNodeId(nodeId));
		if(null != info) {
			return new BaseResponse<String>().error("已存在绑定");
		}
		Map<String, Object> dsnmap = new HashMap<String, Object>();
		dsnmap.put("dnDatasourceId", dataSourceId);
		List<KusciaDatasourceNodeEvent> dsns = dataSourceNodeMapper.selectAllNotPage(dsnmap);
		if(null != dsns && dsns.size() > 0) {
			return new BaseResponse<String>().error("数据源暂时不支持被多次绑定");
		}
		KusciaDatasourceEvent dsInfo = dataSourceMapper.selectByKey(dataSourceId);
		KusciaNodeEvent node = nodeMapper.selectByKey(nodeId);
		KusciaApiInfo apiInfo = new KusciaApiInfo(node.getNodeProtocol(), node.getNodeGrpc()).ext(node.getNodeToken(), node.getNodeCert(), node.getNodeKey(), node.getNodeCa());
		KusciaDatasourceOssEvent ossInfo = ossMapper
				.selectByInfo(new KusciaDatasourceOss().setOssDatasourceId(dsInfo.getDatasourceId()));
		KusciaOssDataSourceInfo dsOss = new KusciaOssDataSourceInfo(ossInfo.getOssEndpoint(), ossInfo.getOssBucket(), 
				ossInfo.getOssPrefix(), ossInfo.getOssAccessKeyId(), ossInfo.getOssAccessKeySecret());
		String dsId = dataSourceManager.createDatasource(apiInfo, node.getNodeCode(), dsInfo.getDatasourceName(), dsOss);
		if(null == dsId || StringUtils.isBlank(dsId)) {
			return new BaseResponse<String>().error("远程绑定失败");
		}
		info = new KusciaDatasourceNode()
		.setDnId(IdUtils.SnowFlakeId())
		.setDnDatasourceId(dataSourceId)
		.setDnNodeId(nodeId)
		.setDnDsId(dsId)
		.setDnCreate(new Date());
		int row = dataSourceNodeMapper.insertSelective(info);
		if(row > 0) {
			return new BaseResponse<String>().success("绑定成功");
		}
		return new BaseResponse<String>().error("绑定失败");
	}

	@Override
	public BaseResponse<String> unBindNode(Long dataSourceId, Long nodeId) {
		KusciaDatasourceNodeEvent info = dataSourceNodeMapper.selectByInfo(
				new KusciaDatasourceNode().setDnDatasourceId(dataSourceId).setDnNodeId(nodeId));
		if(null == info) {
			return new BaseResponse<String>().error("不存在绑定");
		}
		KusciaNodeEvent node = nodeMapper.selectByKey(nodeId);
		KusciaApiInfo apiInfo = new KusciaApiInfo(node.getNodeProtocol(), node.getNodeGrpc()).ext(node.getNodeToken(), node.getNodeCert(), node.getNodeKey(), node.getNodeCa());
		dataSourceManager.removeDataSource(apiInfo, node.getNodeCode(),info.getDnDsId());
		int row = dataSourceNodeMapper.deleteByKey(info.getDnId());
		if(row > 0) {
			return new BaseResponse<String>().success("解绑成功");
		}
		return new BaseResponse<String>().error("解绑失败");
	}
	
	@Override
	public KusciaDatasourceOssEvent getDatasourceOss(Long dataSourceId) {
		KusciaDatasourceOssEvent ossInfo = ossMapper
				.selectByInfo(new KusciaDatasourceOss().setOssDatasourceId(dataSourceId));
		return ossInfo;
	}

}
